/*
 * Copyright (c) 2008, Xiong Yingfei, the University of Tokyo
 * All rights reserved.
 */
package ac.jp.u_tokyo.SyncLib;

import java.util.HashMap;
import java.util.Map;

import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;

import ac.jp.u_tokyo.SyncLib.dictionaries.Map2DictMod;
import ac.jp.u_tokyo.SyncLib.util.Helper;

public abstract class Value2Mod
{
	
	private static Map<Class, Value2Mod> _value2ModMap;
	
	static {
		_value2ModMap = new HashMap<Class, Value2Mod>();
		Value2Mod.register(Object.class, Object2PrimitiveMod.INSTANCE);
		Value2Mod.register(Map.class, Map2DictMod.INSTANCE);
	}

	protected static void register(Class value, Value2Mod mod) {
		_value2ModMap.put(value, mod);
	}
	
	private static Value2Mod get(Class type) {
		if (_value2ModMap.containsKey(type)) return _value2ModMap.get(type);
		
		for (Class i : type.getInterfaces()) {
			if (_value2ModMap.containsKey(i)) return _value2ModMap.get(i);
		}
		
		type = type.getSuperclass();
		while (type != null) {
			if (_value2ModMap.containsKey(type)) return _value2ModMap.get(type);
			type = type.getSuperclass();
		}

		assert false : "Object is not registered!";
		return null;
	}
	
	protected abstract<T> Mod<T> findModImpl(T source, T target);

	public static<T> Mod<T> findMod(T source, T target){
		if (Helper.areEqual(source, target))
			return NullMod.INSTANCE;
		else if (target == null)
			return new PrimMod<T>(target);
		else {
			return get(target.getClass()).findModImpl(source, target);
		}
	}
}

@Aspect
class AssertAspect {
	
	@AfterReturning(pointcut="execution(* findMod(..)) && args(source, target)", 
			returning="result")
	public void checkFindMod(Mod result, Object source, Object target) {
		assert result == null || 
			target == null && result.apply(source) == null|| 
			target.equals(result.apply(source));
	}
}
